/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.virtual.services;

import offset.nodes.server.core.services.XMLToJCRUpdater;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Node;
import javax.jcr.Session;
import offset.nodes.Constants;
import offset.nodes.client.veditor.model.DataModel;
import offset.nodes.server.servlet.EmptyFilter;
import offset.nodes.server.servlet.NodeObserver;
import offset.nodes.server.servlet.XMLFilter;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 *
 * @author Walter Lütgenau
 */
public class SecondaryQueryFilter extends EmptyFilter implements XMLFilter, NodeObserver {
    SecondaryQueryInfo[] secondaryQueries;
    int secondaryQuery = 0;
    XMLToJCRUpdater observable;
    Session session;
    int level = 0;
    public static final int STATE_CREATING_PRIMARY = 0;
    public static final int STATE_PROCESSING_SECONDARY_ENVELOPE = 1;
    public static final int STATE_CREATING_SECONDARY_ROOT = 2;
    public static final int STATE_CREATING_SECONDARY = 3;
    int state = STATE_CREATING_PRIMARY;
    
    String userPropertyPrimaryQuery;
    String commentPropertyPrimaryQuery;
    String userName;
    String comment;

    String primaryUuid = null;
    
    public SecondaryQueryFilter(Session session, XMLToJCRUpdater observable, 
            String userName, String comment,
            String userPropertyPrimaryQuery, String commentPropertyPrimaryQuery, 
            SecondaryQueryInfo[] secondaryQueries) {
    	this.session = session;
        this.secondaryQueries = secondaryQueries;
        this.observable = observable;
        this.userPropertyPrimaryQuery = userPropertyPrimaryQuery;
        this.commentPropertyPrimaryQuery = commentPropertyPrimaryQuery;
        this.userName = userName;
        this.comment = comment;
        
        observable.addNodeObserver(this);
    }

    public void nodeCreated(Node node) {
        if (level == 0)
            try {
                if (state == STATE_CREATING_PRIMARY) {
                    session.save();
                    if (node.isNodeType(Constants.JCR_REFERENCEABLE))
                        primaryUuid = node.getUUID();
                    state = STATE_PROCESSING_SECONDARY_ENVELOPE;

                } 
            } catch (Exception ex) {
                Logger.getLogger(SecondaryQueryFilter.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ( level == 0 && getName(uri, localName, qName).equals(DataModel.ELEMENT_DOCUMENT)) 
            return;
        
        if ( level == 0 && state == STATE_CREATING_SECONDARY_ROOT) {
            state = STATE_PROCESSING_SECONDARY_ENVELOPE;
            return;
        }
        
        level--;
        getOutputHandler().endElement(uri, localName, qName);
        if ( level == 0 && state == STATE_CREATING_SECONDARY)
            state = STATE_CREATING_SECONDARY_ROOT;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        AttributesImpl attributes;
        
        switch(state) {
            case STATE_CREATING_PRIMARY:
                if ( getName(uri, localName, qName).equals(DataModel.ELEMENT_DOCUMENT))
                    return;
                
                attributes = new AttributesImpl(atts);
                if ( userPropertyPrimaryQuery != null && userName != null) {
                    attributes.addAttribute("", "", userPropertyPrimaryQuery, "CDATA", userName);
                    if ( commentPropertyPrimaryQuery != null && comment != null)
                        attributes.addAttribute("", "", commentPropertyPrimaryQuery, "CDATA", comment);
                }
                getOutputHandler().startElement(uri, localName, qName, attributes);
                level++;
                break;
                
            case STATE_CREATING_SECONDARY:
                getOutputHandler().startElement(uri, localName, qName, atts);
                level++;
                break;
                
            case STATE_PROCESSING_SECONDARY_ENVELOPE:
                secondaryQuery = Integer.parseInt(getName(uri,localName,qName).substring(DataModel.SECONDARY_QUERY.length()-1))-1;
                state = STATE_CREATING_SECONDARY_ROOT;
                observable.setParent(secondaryQueries[secondaryQuery].getDataRoot());
                break;
                
            case STATE_CREATING_SECONDARY_ROOT:
                attributes = new AttributesImpl(atts);
                attributes.addAttribute("", "", secondaryQueries[secondaryQuery].getReferenceProperty(), "CDATA", primaryUuid);
                if ( secondaryQueries[secondaryQuery].getUserProperty() != null && userName != null) {
                    attributes.addAttribute("", "", secondaryQueries[secondaryQuery].getUserProperty(), "CDATA", userName);
                    if ( secondaryQueries[secondaryQuery].getCommentProperty() != null && comment != null)
                        attributes.addAttribute("", "", secondaryQueries[secondaryQuery].getCommentProperty(), "CDATA", comment);
                }
                observable.addExtendOnlyProperty(qName, secondaryQueries[secondaryQuery].getReferenceProperty());
                
                getOutputHandler().startElement(uri, localName, qName, attributes);
                state = STATE_CREATING_SECONDARY;
                level++;
                break;
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        getOutputHandler().characters(ch, start, length);
    }
    
    String getName(String uri, String localName, String qName) {
        return qName;
    }    

}
